import {Col, Collapse, Descriptions, Form, Input, Row} from "antd";
import React, {FC, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from "react";
import Config from "../../Config";
import "./css/BaseForm.less";
import GlobalIcon from "../../global/GlobalIcon.tsx";
import useDebounce from "../../customUse/useDebounce.tsx";
import useStateRef from "../../customUse/useStateRef.tsx";
import {isArray, isBoolean, isNumber, isObject} from "../../utils";
import BaseFormItem from "./BaseFormItem";


interface BaseFormProps {
    menuId: string,
    view: any[],
    hideValid?: boolean | undefined,
    init: any,
    initValues?: any,
    children?: any,
    formProps?: any,
    desProps?: any
    isDisabledForm?: boolean,
    labelWidth?: number,
    formItemLayout?: number,
    layout?: string,
    isSearch?: boolean,
    onSubmit?: Function,
    onValuesChange?: Function,
    onRemoveView?: Function
}

const BaseForm: FC<BaseFormProps> = (props) => {
    const [form] = Form.useForm();
    const viewRef = useRef([]);
    const hiddenHeight: number = props.layout === "vertical" ? 65 : 45;
    const [isExpend, setIsExpend] = useState<boolean>(true),
        [height, setHeight] = useState<number | string>(hiddenHeight),
        [view, setView] = useStateRef([], viewRef);

    const updateView = useCallback((updateObjs: any[] = []) => {
        updateObjs.forEach((item: any) => {
            const {newOpt = {}, field}: { newOpt: any, field: string } = item;
            let node: any = viewRef.current.find(k => (k.field === field));
            if (!node) {
                return false
            }
            for (let key in newOpt) {
                if (isObject(node[key])) {
                    node[key] = {
                        ...node[key],
                        ...newOpt[key]
                    };
                } else {
                    node[key] = newOpt[key];
                }
            }
        });
        setView([...viewRef.current]);
    }, [view]);

    const formatParams: Function = useCallback((params: any) => {
        const {view = []}: {
            view: any[]
        } = props;
        let newValues: any = {};
        view.forEach((item: any) => {
            if (item.isSubmit) {
                let newValue: string | string[] = "";
                let dateFormat = item.props.subFormat || Config.dateFormat.date;

                if (isArray(params[item.field])) {
                    newValue = params[item.field].map((node: any) => {
                        if (isObject(node) && node.format) {
                            return node.format(dateFormat).replace('&', ' ')
                        } else if (isNumber(node) || isBoolean(node)) {
                            return node;
                        } else {
                            return node || '';
                        }
                    })
                } else if (isObject(params[item.field]) && params[item.field].format) {
                    newValue = params[item.field].format(dateFormat).replace('&', ' ');
                } else if (isNumber(params[item.field]) || isBoolean(params[item.field])) {
                    newValue = params[item.field];
                } else {
                    newValue = params[item.field] || '';
                }
                newValues[item.field] = newValue;
            }
        });
        return newValues;
    }, [props.view]);

    const onValuesChange: Function = useDebounce((changedValues: any, allValues: any) => {
        props.onValuesChange && props.onValuesChange(changedValues, allValues)
    }, 500, [props.onValuesChange]);

    const onExpendForm = useCallback((isExpend: boolean) => {
        setHeight(isExpend ? "auto" : hiddenHeight);
        setIsExpend(!isExpend);
    }, [isExpend]);

    const onRemoveView = useCallback((field: string) => {
        let newView = [...viewRef.current];
        let nodeIndex: any = newView.findIndex(k => (k.field === field));
        newView.splice(nodeIndex, 1);
        setView(newView);
        props.onRemoveView && props.onRemoveView(field);
    }, [props.onRemoveView]);

    const onFinish = useCallback((values: any) => {
        let params: any = formatParams(values);
        props.onSubmit && props.onSubmit(params);
    }, [props.view]);

    useEffect(() => {
        if (JSON.stringify(props.view) !== JSON.stringify(viewRef.current)) {
            setView(props.view || []);
        }
    }, [props.view]);

    useImperativeHandle(props.init, () => {
        let newValidateFields = form.validateFields;
        form.validateFields = async (nameList: any[], config: any) => {
            let values = await newValidateFields(nameList, config);
            let newValues: any = {};
            for (let key: string in values) {
                if (values[key] && isObject(values[key])) {
                    newValues = {
                        ...newValues,
                        ...values[key]
                    }
                } else {
                    newValues[key] = values[key];
                }
            }
            return newValues;
        }
        form.updateView = updateView;
        return form;
    });

    const renderExpend = useMemo(() => {
        if (!props.isSearch) {
            return null;
        }
        if (props.isSearch && view.length < 4) {
            return null;
        }
        return (<div onClick={() => onExpendForm(isExpend)}
                     className="sf_core_data_form_search_expend">
            <GlobalIcon name={isExpend ? "icon-launch" : "icon-put-away"}/>
        </div>)
    }, [isExpend, props.isSearch, view]);


    const renderBaseFormItem = useMemo(() => {
        let {
            menuId,
            desProps = {},
            labelWidth = 150,
            layout = "horizontal",
            formItemLayout = 1,
            initValues = {},
            hideValid = false
        }:
            {
                menuId: string,
                layout?: string,
                desProps?: any,
                labelWidth?: number,
                formItemLayout?: number,
                initValues?: any,
                hideValid?: boolean | undefined
            } = props;
        let newView: any = {}, isGroup: boolean = false;
        let colLayout = Config.formLayoutList[formItemLayout];
        view.forEach((item: any) => {
            if (item.group) {
                isGroup = true;
                newView[item.field] = {
                    ...item,
                    children: []
                };
            } else if (newView[item.groupId]) {
                newView[item.groupId].children.push({...item})
            } else {
                newView[item.field] = {...item}
            }
        });

        if (isGroup) {
            return (
                <Collapse className="sf_core_data_form_collapse" defaultActiveKey={Object.keys(newView)}>
                    {Object.keys(newView).map((key: string) => {
                        let item: any = newView[key];
                        return (
                            <Collapse.Panel key={key} header={item.title}>
                                <Descriptions
                                    bordered
                                    column={colLayout}
                                    labelStyle={{minWidth: `${labelWidth}px`, wordBreak: 'break-word'}}
                                    contentStyle={{width: `${500}px`}}
                                    layout={layout}
                                    size='small'
                                    className="sf_core_data_form_descriptions"
                                    {...desProps}>
                                    {item.children.map((node: any) => {
                                        let style: any, {hidden = false, oneLine = false, hiddenGroup = false}:
                                            {
                                                hidden: boolean,
                                                oneLine: boolean,
                                                hiddenGroup: boolean
                                            } = node;
                                        let spanNum: number = 1;
                                        if (oneLine) {
                                            spanNum = formItemLayout || 1;
                                        }
                                        if (hidden || hiddenGroup) {
                                            style = {display: "none"}
                                        }

                                        // 判断是否为整体禁用状态
                                        if (props.isDisabledForm !== undefined) {
                                            // 判断是否为整体禁用状态
                                            if (props.isDisabledForm) {
                                                item.props = {
                                                    ...item.props,
                                                    disabled: props.isDisabledForm
                                                }
                                            } else if (item.ruleLimit) {
                                                if (!item.ruleLimit.editable) {
                                                    item.props = {
                                                        ...item.props,
                                                        disabled: true
                                                    }
                                                } else {
                                                    item.props = {
                                                        ...item.props,
                                                        disabled: false
                                                    }
                                                }
                                                if (item.ruleLimit.nullable) {
                                                    item.required = true;
                                                } else {
                                                    item.required = false;
                                                }
                                                if (!item.ruleLimit.visible) {
                                                    style = {display: "none"}
                                                }
                                            }
                                        }
                                        return (
                                            <Descriptions.Item
                                                key={node.field}
                                                span={spanNum}
                                                style={style}
                                                label={<div>
                                                    <span>{node.title + ":"}</span>
                                                    <span style={{color: "red"}}>{node.required ? "*" : ''}</span>
                                                </div>}
                                                // styles={labelStyle}
                                                // labelStyle={{width: `${labelWidth}px`, wordBreak: 'break-word'}}
                                            >
                                                <BaseFormItem
                                                    menuId={menuId}
                                                    initValue={initValues[node.field]}
                                                    viewItem={node}
                                                    hideValid={hideValid}
                                                    onRemove={onRemoveView}
                                                />
                                            </Descriptions.Item>
                                        )
                                    })}
                                </Descriptions>
                            </Collapse.Panel>
                        )
                    })}
                </Collapse>
            )
        } else {
            return (
                <Descriptions
                    bordered
                    layout={layout}
                    size='small'
                    column={colLayout}
                    labelStyle={{minWidth: `${labelWidth}px`, wordBreak: 'break-word'}}
                    contentStyle={{width: `${500}px`}}
                    className="sf_core_data_form_descriptions"
                    {...desProps}>
                    {Object.keys(newView).map((key: string) => {
                        let item: any = newView[key], style: any, labelStyle: any = {},
                            {hidden = false, oneLine = false, hiddenGroup = false, hideLabel = false}:
                                {
                                    hidden: boolean,
                                    oneLine: boolean,
                                    hiddenGroup: boolean,
                                    hideLabel: boolean,
                                } = item;
                        let spanNum: number = 1;
                        if (oneLine) {
                            spanNum = formItemLayout || 1;
                        }
                        if (hideLabel) {
                            labelStyle = {display: 'none'}
                        }
                        if (hidden || hiddenGroup) {
                            style = {display: "none"}
                        }
                        // 判断是否为整体禁用状态
                        if (props.isDisabledForm !== undefined) {
                            // 判断是否为整体禁用状态
                            if (props.isDisabledForm) {
                                item.props = {
                                    ...item.props,
                                    disabled: props.isDisabledForm
                                }
                            } else if (item.ruleLimit) {
                                if (!item.ruleLimit.editable) {
                                    item.props = {
                                        ...item.props,
                                        disabled: true
                                    }
                                } else {
                                    item.props = {
                                        ...item.props,
                                        disabled: false
                                    }
                                }
                                if (!item.ruleLimit.nullable) {
                                    item.required = true;
                                } else {
                                    item.required = false;
                                }
                                if (!item.ruleLimit.visible) {
                                    style = {display: "none"}
                                }
                            }
                        }
                        return (
                            <Descriptions.Item
                                span={spanNum}
                                key={item.field}
                                style={style}
                                label={<div>
                                    <span>{item.title + ":"}</span>
                                    <span style={{color: "red"}}>{item.required ? "*" : ''}</span>
                                </div>}
                                // styles={{width: `${labelWidth}px`, wordBreak: 'break-word', ...labelStyle}}
                                styles={labelStyle}
                            >
                                <BaseFormItem
                                    menuId={menuId}
                                    initValue={!initValues[item.field] ? item.initValue : initValues[item.field]}
                                    viewItem={item}
                                    hideValid={hideValid}
                                    onRemove={onRemoveView}
                                />
                            </Descriptions.Item>
                        )
                    })}
                </Descriptions>
            )
        }
    }, [props, view]);

    const renderBaseForm = useMemo(() => {
        const {formProps = {labelAlign: 'left'}}: {
            formProps?: any
        } = props;
        let styleForm: any = {};
        if (props.isSearch) {
            styleForm.height = height;
        }
        return (
            <div className="sf_core_data_form">
                <Form
                    form={form}
                    onFinish={onFinish}
                    onValuesChange={onValuesChange}
                    {...formProps}
                >
                    <Row>
                        <Col span={24} className={props.isSearch ? "sf_core_data_form_search_box" : ''}
                             style={styleForm}>
                            {renderBaseFormItem}
                            {props.children}
                        </Col>
                        <Col span={24}>
                            {renderExpend}
                        </Col>
                    </Row>
                </Form>
            </div>
        )
    }, [props, isExpend, view]);

    return (renderBaseForm)
};

// @ts-ignore
Input.TextArea.renderShow = (value) => {
    if (!value) {
        return "";
    }
    return <pre className="c-pre c-form-textarea">{value}</pre>
};


export default React.memo(BaseForm);